From 706fcdf4de51d825c80d3695664df34bc5ea01ff Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Mon, 17 Oct 2005 16:22:05 +0100 Subject: [PATCH] Have xenstored initialise its connections, meaning that xend can be out of that loop completely -- the xc_init_store, initDomainStore calls can all go. Have xenstored understand where the local domain information goes. Xend no longer has to generate a path and pass it to xenstored through xs_introduce_domain -- we just allow xenstored to generate the path, and then call GetDomainPath later. There is still some work required to tidy this up. Change the uuid module to generate uuids as lists of bytes, not in the stringified form. Added a unit test for that module. Change the semantics of Xend restart, relying on these changes to the xenstored semantics and earlier changes to add an opaque handle to the hypervisor's domain-specific data block. The semantics are now clearer, as Xend can validate whether the details in the store match the current live domain. Added a usage statement to xenstored. Some of this code is by Steven Hand. Signed-off-by: Ewan Mellor --- .../drivers/xen/privcmd/privcmd.c | 37 ----- .../drivers/xen/xenbus/xenbus_comms.c | 15 +- .../drivers/xen/xenbus/xenbus_probe.c | 138 ++++++++++++++---- .../include/asm-xen/linux-public/privcmd.h | 2 - tools/libxc/xc_misc.c | 5 - tools/libxc/xenctrl.h | 15 +- tools/python/xen/lowlevel/xc/xc.c | 24 --- tools/python/xen/lowlevel/xs/xs.c | 10 +- tools/python/xen/xend/XendCheckpoint.py | 9 +- tools/python/xen/xend/XendDomain.py | 39 ++--- tools/python/xen/xend/XendDomainInfo.py | 110 +++++++------- tools/python/xen/xend/uuid.py | 20 ++- tools/python/xen/xend/xenstore/xsutil.py | 4 +- tools/xenstore/xenstored_core.c | 41 +++++- tools/xenstore/xenstored_domain.c | 78 +++++++--- tools/xenstore/xs.c | 6 +- tools/xenstore/xs.h | 4 +- 17 files changed, 311 insertions(+), 246 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index 6ed338bab1..b13f22a771 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include #include @@ -219,41 +217,6 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, } break; - case IOCTL_PRIVCMD_INITDOMAIN_STORE: { - extern int do_xenbus_probe(void*); - unsigned long page; - - if (xen_start_info->store_evtchn != 0) { - ret = xen_start_info->store_mfn; - break; - } - - /* Allocate page. */ - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - ret = -ENOMEM; - break; - } - - /* We don't refcnt properly, so set reserved on page. - * (this allocation is permanent) */ - SetPageReserved(virt_to_page(page)); - - /* Initial connect. Setup channel and page. */ - xen_start_info->store_evtchn = data; - xen_start_info->store_mfn = - pfn_to_mfn(virt_to_phys((void *)page) >> - PAGE_SHIFT); - ret = xen_start_info->store_mfn; - - /* - ** Complete initialization of xenbus (viz. set up the - ** connection to xenstored now that it has started). - */ - kthread_run(do_xenbus_probe, NULL, "xenbus_probe"); - } - break; - default: ret = -EINVAL; break; diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c index e3863a2c79..a1e83f7800 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -36,7 +36,11 @@ #include #include "xenbus_comms.h" -static int xenbus_irq; +static int xenbus_irq = 0; + +extern void xenbus_probe(void *); +extern int xenstored_ready; +static DECLARE_WORK(probe_work, xenbus_probe, NULL); DECLARE_WAIT_QUEUE_HEAD(xb_waitq); @@ -47,6 +51,11 @@ static inline struct xenstore_domain_interface *xenstore_domain_interface(void) static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs) { + if(unlikely(xenstored_ready == 0)) { + xenstored_ready = 1; + schedule_work(&probe_work); + } + wake_up(&xb_waitq); return IRQ_HANDLED; } @@ -169,10 +178,6 @@ int xb_init_comms(void) if (xenbus_irq) unbind_evtchn_from_irqhandler(xenbus_irq, &xb_waitq); - xenbus_irq = 0; - - if (!xen_start_info->store_evtchn) - return 0; err = bind_evtchn_to_irqhandler( xen_start_info->store_evtchn, wake_waiting, diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index e04798a562..e5c9de1139 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -27,16 +27,25 @@ */ #define DEBUG -#include -#include -#include #include #include #include #include #include -#include +#include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "xenbus_comms.h" extern struct semaphore xenwatch_mutex; @@ -634,15 +643,19 @@ void xenbus_resume(void) bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); } + +/* A flag to determine if xenstored is 'ready' (i.e. has started) */ +int xenstored_ready = 0; + + int register_xenstore_notifier(struct notifier_block *nb) { int ret = 0; - if (xen_start_info->store_evtchn) { + if(xenstored_ready > 0) ret = nb->notifier_call(nb, 0, NULL); - } else { + else notifier_chain_register(&xenstore_chain, nb); - } return ret; } @@ -654,22 +667,11 @@ void unregister_xenstore_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(unregister_xenstore_notifier); -/* -** Called either from below xenbus_probe_init() initcall (for domUs) -** or, for dom0, from a thread created in privcmd/privcmd.c (after -** the user-space tools have invoked initDomainStore()) -*/ -int do_xenbus_probe(void *unused) -{ - int err = 0; - /* Initialize the interface to xenstore. */ - err = xs_init(); - if (err) { - printk("XENBUS: Error initializing xenstore comms:" - " %i\n", err); - return err; - } + +void xenbus_probe(void *unused) +{ + BUG_ON((xenstored_ready <= 0)); /* Enumerate devices in xenstore. */ xenbus_probe_devices(&xenbus_frontend); @@ -682,27 +684,101 @@ int do_xenbus_probe(void *unused) /* Notify others that xenstore is up */ notifier_call_chain(&xenstore_chain, 0, 0); - return 0; + return; +} + + +static struct proc_dir_entry *xsd_mfn_intf; +static struct proc_dir_entry *xsd_port_intf; + + +static int xsd_mfn_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + len = sprintf(page, "%ld", xen_start_info->store_mfn); + *eof = 1; + return len; } +static int xsd_port_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d", xen_start_info->store_evtchn); + *eof = 1; + return len; +} + + static int __init xenbus_probe_init(void) { - if (xen_init() < 0) + int err = 0; + /* + ** Domain0 doesn't have a store_evtchn or store_mfn yet. + */ + int dom0 = (xen_start_info->store_evtchn == 0); + + printk("xenbus_probe_init\n"); + + if (xen_init() < 0) { + printk("xen_init failed\n"); return -ENODEV; + } + /* Register ourselves with the kernel bus & device subsystems */ bus_register(&xenbus_frontend.bus); bus_register(&xenbus_backend.bus); device_register(&xenbus_frontend.dev); device_register(&xenbus_backend.dev); - /* - ** Domain0 doesn't have a store_evtchn yet - this will - ** be set up later by xend invoking initDomainStore() - */ - if (!xen_start_info->store_evtchn) - return 0; + if (dom0) { + + unsigned long page; + evtchn_op_t op = { 0 }; + + + /* Allocate page. */ + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + /* We don't refcnt properly, so set reserved on page. + * (this allocation is permanent) */ + SetPageReserved(virt_to_page(page)); + + xen_start_info->store_mfn = + pfn_to_mfn(virt_to_phys((void *)page) >> + PAGE_SHIFT); + + /* Next allocate a local port which xenstored can bind to */ + op.cmd = EVTCHNOP_alloc_unbound; + op.u.alloc_unbound.dom = DOMID_SELF; + op.u.alloc_unbound.remote_dom = 0; + + BUG_ON(HYPERVISOR_event_channel_op(&op)); + xen_start_info->store_evtchn = op.u.alloc_unbound.port; + + /* And finally publish the above info in /proc/xen */ + if((xsd_mfn_intf = create_xen_proc_entry("xsd_mfn", 0400))) + xsd_mfn_intf->read_proc = xsd_mfn_read; + if((xsd_port_intf = create_xen_proc_entry("xsd_port", 0400))) + xsd_port_intf->read_proc = xsd_port_read; + } + + /* Initialize the interface to xenstore. */ + err = xs_init(); + if (err) { + printk("XENBUS: Error initializing xenstore comms: %i\n", err); + return err; + } + + if (!dom0) { + xenstored_ready = 1; + xenbus_probe(NULL); + } - do_xenbus_probe(NULL); return 0; } diff --git a/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h b/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h index 1246dbd64b..292ade02b8 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h +++ b/linux-2.6-xen-sparse/include/asm-xen/linux-public/privcmd.h @@ -76,8 +76,6 @@ typedef struct privcmd_blkmsg _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) #define IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN \ _IOC(_IOC_READ, 'P', 4, sizeof(unsigned long)) -#define IOCTL_PRIVCMD_INITDOMAIN_STORE \ - _IOC(_IOC_READ, 'P', 5, 0) #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index ab263689c5..b0987d2a47 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -131,11 +131,6 @@ int xc_msr_write(int xc_handle, int cpu_mask, int msr, unsigned int low, return rc; } -long xc_init_store(int xc_handle, int remote_port) -{ - return ioctl(xc_handle, IOCTL_PRIVCMD_INITDOMAIN_STORE, remote_port); -} - /* * Local variables: * mode: C diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 818a29df24..98408f25bf 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -236,12 +236,12 @@ int xc_domain_getinfolist(int xc_handle, xc_domaininfo_t *info); /** - * This function returns information about one domain. This information is - * more detailed than the information from xc_domain_getinfo(). + * This function returns information about the execution context of a + * particular vcpu of a domain. * * @parm xc_handle a handle to an open hypervisor interface * @parm domid the domain to get information from - * @parm info a pointer to an xc_domaininfo_t to store the domain information + * @parm vcpu the vcpu number * @parm ctxt a pointer to a structure to store the execution context of the * domain * @return 0 on success, -1 on failure @@ -489,15 +489,6 @@ int xc_dom0_op(int xc_handle, dom0_op_t *op); int xc_version(int xc_handle, int cmd, void *arg); -/* Initializes the store (for dom0) - remote_port should be the remote end of a bound interdomain channel between - the store and dom0. - - This function returns a shared frame that should be passed to - xs_introduce_domain - */ -long xc_init_store(int xc_handle, int remote_port); - /* * MMU updates. */ diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 4a11ef77c5..927b1ccdc5 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -862,23 +862,6 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self, return zero; } -static PyObject *pyxc_init_store(PyObject *self, PyObject *args, - PyObject *kwds) -{ - XcObject *xc = (XcObject *)self; - - int remote_port; - - static char *kwd_list[] = { "remote_port", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, - &remote_port) ) - return NULL; - - return PyInt_FromLong(xc_init_store(xc->xc_handle, remote_port)); -} - - static PyMethodDef pyxc_methods[] = { { "handle", (PyCFunction)pyxc_handle, @@ -1158,13 +1141,6 @@ static PyMethodDef pyxc_methods[] = { " mem_kb [long]: .\n" "Returns: [int] 0 on success; -1 on error.\n" }, - { "init_store", - (PyCFunction)pyxc_init_store, - METH_VARARGS | METH_KEYWORDS, "\n" - "Initialize the store event channel and return the store page mfn.\n" - " remote_port [int]: store event channel port number.\n" - "Returns: [int] mfn on success; <0 on error.\n" }, - { NULL, NULL, 0, NULL } }; diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index b676419227..b5ce2c357b 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -686,7 +686,6 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args, " dom [int] : domain id\n" \ " page [long] : address of domain's xenstore page\n" \ " port [int] : port the domain is using for xenstore\n" \ - " path [string]: path to the domain's data in xenstore\n" \ "\n" \ "Returns None on success.\n" \ "Raises RuntimeError on error.\n" \ @@ -695,12 +694,11 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args, static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "dom", "page", "port", "path", NULL }; - static char *arg_spec = "iiis|"; + static char *kwd_spec[] = { "dom", "page", "port", NULL }; + static char *arg_spec = "iii"; domid_t dom = 0; unsigned long page = 0; unsigned int port = 0; - char *path = NULL; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; @@ -709,10 +707,10 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args, if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, - &dom, &page, &port, &path)) + &dom, &page, &port)) goto exit; Py_BEGIN_ALLOW_THREADS - xsval = xs_introduce_domain(xh, dom, page, port, path); + xsval = xs_introduce_domain(xh, dom, page, port); Py_END_ALLOW_THREADS if (!xsval) { PyErr_SetFromErrno(PyExc_RuntimeError); diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index d8ae85b91e..25c496add0 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -143,15 +143,13 @@ def restore(xd, fd): if m: store_mfn = int(m.group(2)) dominfo.setStoreRef(store_mfn) - log.debug("IntroduceDomain %d %d %d %s", + log.debug("IntroduceDomain %d %d %d", dominfo.getDomid(), store_mfn, - dominfo.store_channel, - dominfo.getDomainPath()) + dominfo.store_channel) IntroduceDomain(dominfo.getDomid(), store_mfn, - dominfo.store_channel, - dominfo.getDomainPath()) + dominfo.store_channel) else: m = re.match(r"^(console-mfn) (\d+)$", line) if m: @@ -171,6 +169,7 @@ def forkHelper(cmd, fd, inputHandler, closeToChild): if closeToChild: child.tochild.close() + lasterr = "error unknown" try: fds = [child.fromchild.fileno(), child.childerr.fileno()] diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 6f1ab9b84e..802c53f689 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -21,8 +21,10 @@ Nothing here is persistent (across reboots). Needs to be persistent for one uptime. """ -import os + import logging +import os +import sys import threading import xen.lowlevel.xc @@ -62,8 +64,11 @@ class XendDomain: self.domains_lock.acquire() try: - self.refresh(True) + self._add_domain( + XendDomainInfo.recreate(self.xen_domains()[PRIV_DOMAIN], + True)) self.dom0_setup() + self.refresh(True) finally: self.domains_lock.release() @@ -178,25 +183,23 @@ class XendDomain: 'Cannot recreate information for dying domain %d.' ' Xend will ignore this domain from now on.', doms[d]['dom']) + elif d == PRIV_DOMAIN: + log.fatal( + "No record of privileged domain %d! Terminating.", d) + sys.exit(1) else: try: - dominfo = XendDomainInfo.recreate(doms[d]) - self._add_domain(dominfo) + self._add_domain( + XendDomainInfo.recreate(doms[d], False)) except: - if d == PRIV_DOMAIN: - log.exception( - "Failed to recreate information for domain " - "%d. Doing nothing except crossing my " - "fingers.", d) - else: - log.exception( - "Failed to recreate information for domain " - "%d. Destroying it in the hope of " - "recovery.", d) - try: - xc.domain_destroy(dom = d) - except: - log.exception('Destruction of %d failed.', d) + log.exception( + "Failed to recreate information for domain " + "%d. Destroying it in the hope of " + "recovery.", d) + try: + xc.domain_destroy(dom = d) + except: + log.exception('Destruction of %d failed.', d) ## public: diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 79fdd38a9a..0ad6f5a7dd 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -28,7 +28,6 @@ import logging import string import time import threading -import errno import xen.lowlevel.xc from xen.util import asserts @@ -42,7 +41,7 @@ from xen.xend.XendBootloader import bootloader from xen.xend.XendError import XendError, VmError from xen.xend.XendRoot import get_component -from uuid import getUuid +import uuid from xen.xend.xenstore.xstransact import xstransact from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain @@ -153,7 +152,7 @@ def create(config): log.debug("XendDomainInfo.create(%s)", config) - vm = XendDomainInfo(getUuid(), parseConfig(config)) + vm = XendDomainInfo(uuid.create(), parseConfig(config)) try: vm.construct() vm.initDomain() @@ -169,7 +168,7 @@ def create(config): raise -def recreate(xeninfo): +def recreate(xeninfo, priv): """Create the VM object for an existing domain. The domain must not be dying, as the paths in the store should already have been removed, and asking us to recreate them causes problems.""" @@ -179,39 +178,52 @@ def recreate(xeninfo): assert not xeninfo['dying'] domid = xeninfo['dom'] + dompath = GetDomainPath(domid) + if not dompath: + raise XendError( + 'No domain path in store for existing domain %d' % domid) try: - dompath = GetDomainPath(domid) - if not dompath: - raise XendError( - 'No domain path in store for existing domain %d' % domid) vmpath = xstransact.Read(dompath, "vm") if not vmpath: raise XendError( 'No vm path in store for existing domain %d' % domid) - uuid = xstransact.Read(vmpath, "uuid") - if not uuid: + uuid1_str = xstransact.Read(vmpath, "uuid") + if not uuid1_str: raise XendError( 'No vm/uuid path in store for existing domain %d' % domid) - log.info("Recreating domain %d, UUID %s.", domid, uuid) + uuid1 = uuid.fromString(uuid1_str) + + uuid2 = xeninfo['handle'] + + if uuid1 != uuid2: + raise XendError( + 'Uuid in store does not match uuid for existing domain %d: ' + '%s != %s' % (domid, uuid1_str, uuid.toString(uuid2))) + + log.info("Recreating domain %d, UUID %s.", domid, uuid1_str) - vm = XendDomainInfo(uuid, xeninfo, domid, True) + vm = XendDomainInfo(uuid2, xeninfo, domid, dompath, True) except Exception, exn: log.warn(str(exn)) - uuid = getUuid() + if priv: + new_uuid = [0 for i in range(0, 16)] + else: + new_uuid = uuid.create() - log.info("Recreating domain %d with new UUID %s.", domid, uuid) + log.info("Recreating domain %d with new UUID %s.", domid, + uuid.toString(new_uuid)) - vm = XendDomainInfo(uuid, xeninfo, domid, True) + vm = XendDomainInfo(new_uuid, xeninfo, domid, dompath, True) vm.removeDom() vm.storeVmDetails() vm.storeDomDetails() - vm.create_channel() - if domid == 0: - vm.initStoreConnection() + if domid != 0: + # Setup store and console channels + vm.create_channels() vm.refreshShutdown(xeninfo) return vm @@ -225,12 +237,12 @@ def restore(config): log.debug("XendDomainInfo.restore(%s)", config) - uuid = sxp.child_value(config, 'uuid') - vm = XendDomainInfo(uuid, parseConfig(config)) + vm = XendDomainInfo(uuid.fromString(sxp.child_value(config, 'uuid')), + parseConfig(config)) try: vm.construct() vm.configure() - vm.create_channel() + vm.create_channels() vm.storeVmDetails() vm.storeDomDetails() vm.refreshShutdown() @@ -355,9 +367,10 @@ class XendDomainInfo: MINIMUM_RESTART_TIME = 20 - def __init__(self, uuid, info, domid = None, augment = False): + def __init__(self, uuidbytes, info, domid = None, dompath = None, + augment = False): - self.uuid = uuid + self.uuidbytes = uuidbytes self.info = info if domid is not None: @@ -367,11 +380,8 @@ class XendDomainInfo: else: self.domid = None - self.vmpath = VMROOT + uuid - if self.domid is None: - self.dompath = None - else: - self.dompath = DOMROOT + str(self.domid) + self.vmpath = VMROOT + uuid.toString(uuidbytes) + self.dompath = dompath if augment: self.augmentInfo() @@ -440,6 +450,9 @@ class XendDomainInfo: defaultInfo('cpu', lambda: None) defaultInfo('cpu_weight', lambda: 1.0) defaultInfo('vcpus', lambda: 1) + + self.info['vcpus'] = int(self.info['vcpus']) + defaultInfo('vcpu_avail', lambda: (1 << self.info['vcpus']) - 1) defaultInfo('bootloader', lambda: None) defaultInfo('backend', lambda: []) @@ -576,7 +589,7 @@ class XendDomainInfo: def storeVmDetails(self): to_store = { - 'uuid': self.uuid, + 'uuid': uuid.toString(self.uuidbytes), # XXX 'memory/target': str(self.info['memory_KiB']) @@ -651,9 +664,6 @@ class XendDomainInfo: def getDomainPath(self): return self.dompath - def getUuid(self): - return self.uuid - def getVCpuCount(self): return self.info['vcpus'] @@ -921,7 +931,7 @@ class XendDomainInfo: def sxpr(self): sxpr = ['domain', ['domid', self.domid], - ['uuid', self.uuid], + ['uuid', uuid.toString(self.uuidbytes)], ['memory', self.info['memory_KiB'] / 1024]] for e in ROUNDTRIPPING_CONFIG_ENTRIES: @@ -1038,7 +1048,8 @@ class XendDomainInfo: self.domid, self.info['ssidref']) - self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref']) + self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'], + handle = self.uuidbytes) if self.domid < 0: raise VmError('Creating domain failed: name=%s' % @@ -1089,10 +1100,9 @@ class XendDomainInfo: def construct_image(self): """Construct the boot image for the domain. """ - self.create_channel() + self.create_channels() self.image.createImage() - IntroduceDomain(self.domid, self.store_mfn, - self.store_channel, self.dompath) + IntroduceDomain(self.domid, self.store_mfn, self.store_channel) ## public: @@ -1199,7 +1209,7 @@ class XendDomainInfo: self.storeDom(path, port) return port - def create_channel(self): + def create_channels(self): """Create the channels to the domain. """ self.store_channel = self.eventChannel("store/port") @@ -1312,13 +1322,15 @@ class XendDomainInfo: """ new_name = self.generateUniqueName() - new_uuid = getUuid() + new_uuid = uuid.create() + new_uuid_str = uuid.toString(new_uuid) log.info("Renaming dead domain %s (%d, %s) to %s (%s).", - self.info['name'], self.domid, self.uuid, new_name, new_uuid) + self.info['name'], self.domid, uuid.toString(self.uuidbytes), + new_name, new_uuid_str) self.release_devices() self.info['name'] = new_name - self.uuid = new_uuid - self.vmpath = VMROOT + new_uuid + self.uuidbytes = new_uuid + self.vmpath = VMROOT + new_uuid_str self.storeVmDetails() self.preserve() @@ -1384,20 +1396,6 @@ class XendDomainInfo: self.storeDom("control/sysrq", '%c' % key) - def initStoreConnection(self): - ref = xc.init_store(self.store_channel) - if ref and ref >= 0: - self.setStoreRef(ref) - try: - IntroduceDomain(self.domid, ref, self.store_channel, - self.dompath) - except RuntimeError, ex: - if ex.args[0] == errno.EISCONN: - pass - else: - raise - - def infoIsSet(self, name): return name in self.info and self.info[name] is not None diff --git a/tools/python/xen/xend/uuid.py b/tools/python/xen/xend/uuid.py index b37cb17a39..77517e9fbe 100644 --- a/tools/python/xen/xend/uuid.py +++ b/tools/python/xen/xend/uuid.py @@ -36,23 +36,27 @@ def getUuidUuidgen(random = True): cmd += " -r" else: cmd += " -t" - return commands.getoutput(cmd) + return fromString(commands.getoutput(cmd)) def getUuidRandom(): """Generate a random UUID.""" - bytes = [ random.randint(0, 255) for i in range(0, 16) ] - # Encode the variant. - bytes[6] = (bytes[6] & 0x0f) | 0x40 - bytes[8] = (bytes[8] & 0x3f) | 0x80 - f = "%02x" - return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) ) + return [ random.randint(0, 255) for i in range(0, 16) ] #uuidFactory = getUuidUuidgen uuidFactory = getUuidRandom -def getUuid(): +def create(): return uuidFactory() + + +def toString(u): + f = "%02x" + return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(u) ) + +def fromString(s): + s = s.replace('-', '') + return [ int(s[i : i + 2], 16) for i in range(0, 32, 2) ] diff --git a/tools/python/xen/xend/xenstore/xsutil.py b/tools/python/xen/xend/xenstore/xsutil.py index 486a3eeb4d..d2af3c5ac5 100644 --- a/tools/python/xen/xend/xenstore/xsutil.py +++ b/tools/python/xen/xend/xenstore/xsutil.py @@ -19,8 +19,8 @@ def xshandle(): xs_lock.release() return xs_handle -def IntroduceDomain(domid, page, port, path): - return xshandle().introduce_domain(domid, page, port, path) +def IntroduceDomain(domid, page, port): + return xshandle().introduce_domain(domid, page, port) def GetDomainPath(domid): return xshandle().get_domain_path(domid) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 3fbad0728d..a66f7d8a48 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -51,7 +51,7 @@ #include "xenctrl.h" #include "tdb.h" -int event_fd; +extern int eventchn_fd; /* in xenstored_domain.c */ static bool verbose; LIST_HEAD(connections); @@ -319,9 +319,9 @@ static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock) FD_SET(ro_sock, inset); if (ro_sock > max) max = ro_sock; - FD_SET(event_fd, inset); - if (event_fd > max) - max = event_fd; + FD_SET(eventchn_fd, inset); + if (eventchn_fd > max) + max = eventchn_fd; list_for_each_entry(i, &connections, list) { if (i->domain) continue; @@ -1416,15 +1416,37 @@ static void daemonize(void) } +static void usage(void) +{ + fprintf(stderr, +"Usage:\n" +"\n" +" xenstored \n" +"\n" +"where options may include:\n" +"\n" +" --no-domain-init to state that xenstored should not initialise dom0,\n" +" --pid-file giving a file for the daemon's pid to be written,\n" +" --help to output this message,\n" +" --no-fork to request that the daemon does not fork,\n" +" --output-pid to request that the pid of the daemon is output,\n" +" --trace-file giving the file for logging, and\n" +" --verbose to request verbose execution.\n"); +} + + static struct option options[] = { { "no-domain-init", 0, NULL, 'D' }, { "pid-file", 1, NULL, 'F' }, + { "help", 0, NULL, 'H' }, { "no-fork", 0, NULL, 'N' }, { "output-pid", 0, NULL, 'P' }, { "trace-file", 1, NULL, 'T' }, { "verbose", 0, NULL, 'V' }, { NULL, 0, NULL, 0 } }; +extern void dump_conn(struct connection *conn); + int main(int argc, char *argv[]) { int opt, *sock, *ro_sock, max; @@ -1435,7 +1457,7 @@ int main(int argc, char *argv[]) bool no_domain_init = false; const char *pidfile = NULL; - while ((opt = getopt_long(argc, argv, "DF:NPT:V", options, + while ((opt = getopt_long(argc, argv, "DF:HNPT:V", options, NULL)) != -1) { switch (opt) { case 'D': @@ -1444,6 +1466,9 @@ int main(int argc, char *argv[]) case 'F': pidfile = optarg; break; + case 'H': + usage(); + return 0; case 'N': dofork = false; break; @@ -1509,12 +1534,12 @@ int main(int argc, char *argv[]) || listen(*ro_sock, 1) != 0) barf_perror("Could not listen on sockets"); - /* If we're the first, create .perms file for root. */ + /* Setup the database */ setup_structure(); /* Listen to hypervisor. */ if (!no_domain_init) - event_fd = domain_init(); + domain_init(); /* Restore existing connections. */ restore_existing_connections(); @@ -1555,7 +1580,7 @@ int main(int argc, char *argv[]) if (FD_ISSET(*ro_sock, &inset)) accept_connection(*ro_sock, false); - if (FD_ISSET(event_fd, &inset)) + if (FD_ISSET(eventchn_fd, &inset)) handle_event(); list_for_each_entry(i, &connections, list) { diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 74558b1ec9..9ddcf4f728 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -40,9 +40,10 @@ #include static int *xc_handle; -static int eventchn_fd; static int virq_port; +int eventchn_fd = -1; + struct domain { struct list_head list; @@ -79,9 +80,11 @@ static LIST_HEAD(domains); #ifndef TESTING static void evtchn_notify(int port) { + int rc; + struct ioctl_evtchn_notify notify; notify.port = port; - (void)ioctl(event_fd, IOCTL_EVTCHN_NOTIFY, ¬ify); + rc = ioctl(eventchn_fd, IOCTL_EVTCHN_NOTIFY, ¬ify); } #else extern void evtchn_notify(int port); @@ -222,14 +225,14 @@ void handle_event(void) { uint16_t port; - if (read(event_fd, &port, sizeof(port)) != sizeof(port)) + if (read(eventchn_fd, &port, sizeof(port)) != sizeof(port)) barf_perror("Failed to read from event fd"); if (port == virq_port) domain_cleanup(); #ifndef TESTING - if (write(event_fd, &port, sizeof(port)) != sizeof(port)) + if (write(eventchn_fd, &port, sizeof(port)) != sizeof(port)) barf_perror("Failed to write to event fd"); #endif } @@ -247,18 +250,18 @@ bool domain_can_write(struct connection *conn) } static struct domain *new_domain(void *context, unsigned int domid, - unsigned long mfn, int port, - const char *path) + unsigned long mfn, int port) { struct domain *domain; struct ioctl_evtchn_bind_interdomain bind; int rc; + domain = talloc(context, struct domain); domain->port = 0; domain->shutdown = 0; domain->domid = domid; - domain->path = talloc_strdup(domain, path); + domain->path = talloc_asprintf(domain, "/local/domain/%d", domid); domain->interface = xc_map_foreign_range( *xc_handle, domain->domid, getpagesize(), PROT_READ|PROT_WRITE, mfn); @@ -269,13 +272,13 @@ static struct domain *new_domain(void *context, unsigned int domid, talloc_set_destructor(domain, destroy_domain); /* Tell kernel we're interested in this event. */ - bind.remote_domain = domid; - bind.remote_port = port; - rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind); - if (rc == -1) - return NULL; + bind.remote_domain = domid; + bind.remote_port = port; + rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind); + if (rc == -1) + return NULL; + domain->port = rc; - domain->port = rc; domain->conn = new_connection(writechn, readchn); domain->conn->domain = domain; @@ -302,11 +305,10 @@ static struct domain *find_domain_by_domid(unsigned int domid) void do_introduce(struct connection *conn, struct buffered_data *in) { struct domain *domain; - char *vec[4]; + char *vec[3]; unsigned int domid; unsigned long mfn; uint16_t port; - const char *path; if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) { send_error(conn, EINVAL); @@ -321,10 +323,9 @@ void do_introduce(struct connection *conn, struct buffered_data *in) domid = atoi(vec[0]); mfn = atol(vec[1]); port = atoi(vec[2]); - path = vec[3]; /* Sanity check args. */ - if ((port <= 0) || !is_valid_nodename(path)) { + if (port <= 0) { send_error(conn, EINVAL); return; } @@ -333,7 +334,7 @@ void do_introduce(struct connection *conn, struct buffered_data *in) if (domain == NULL) { /* Hang domain off "in" until we're finished. */ - domain = new_domain(in, domid, mfn, port, path); + domain = new_domain(in, domid, mfn, port); if (!domain) { send_error(conn, errno); return; @@ -348,8 +349,7 @@ void do_introduce(struct connection *conn, struct buffered_data *in) /* Check that the given details match the ones we have previously recorded. */ if (port != domain->remote_port || - mfn != domain->mfn || - strcmp(path, domain->path) != 0) { + mfn != domain->mfn) { send_error(conn, EINVAL); return; } @@ -440,10 +440,45 @@ void restore_existing_connections(void) { } +static int dom0_init(void) +{ + int rc, fd, port; + unsigned long mfn; + char str[20]; + struct domain *dom0; + + fd = open("/proc/xen/xsd_mfn", O_RDONLY); + + rc = read(fd, str, sizeof(str)); + str[rc] = '\0'; + mfn = strtoul(str, NULL, 0); + + close(fd); + + fd = open("/proc/xen/xsd_port", O_RDONLY); + + rc = read(fd, str, sizeof(str)); + str[rc] = '\0'; + port = strtoul(str, NULL, 0); + + close(fd); + + + dom0 = new_domain(NULL, 0, mfn, port); + talloc_steal(dom0->conn, dom0); + + evtchn_notify(dom0->port); + + return 0; +} + + + #define EVTCHN_DEV_NAME "/dev/xen/evtchn" #define EVTCHN_DEV_MAJOR 10 #define EVTCHN_DEV_MINOR 201 + /* Returns the event channel handle. */ int domain_init(void) { @@ -484,6 +519,9 @@ int domain_init(void) if (eventchn_fd < 0) barf_perror("Failed to open evtchn device"); + if (dom0_init() != 0) + barf_perror("Failed to initialize dom0 state"); + bind.virq = VIRQ_DOM_EXC; rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_VIRQ, &bind); if (rc == -1) diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index 18e875e801..22710d5d01 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -674,12 +674,12 @@ bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t, */ bool xs_introduce_domain(struct xs_handle *h, unsigned int domid, unsigned long mfn, - unsigned int eventchn, const char *path) + unsigned int eventchn) { char domid_str[MAX_STRLEN(domid)]; char mfn_str[MAX_STRLEN(mfn)]; char eventchn_str[MAX_STRLEN(eventchn)]; - struct iovec iov[4]; + struct iovec iov[3]; sprintf(domid_str, "%u", domid); sprintf(mfn_str, "%lu", mfn); @@ -691,8 +691,6 @@ bool xs_introduce_domain(struct xs_handle *h, iov[1].iov_len = strlen(mfn_str) + 1; iov[2].iov_base = eventchn_str; iov[2].iov_len = strlen(eventchn_str) + 1; - iov[3].iov_base = (char *)path; - iov[3].iov_len = strlen(path) + 1; return xs_bool(xs_talkv(h, NULL, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL)); diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h index 92007458d3..618e6615a6 100644 --- a/tools/xenstore/xs.h +++ b/tools/xenstore/xs.h @@ -130,9 +130,7 @@ bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t, bool xs_introduce_domain(struct xs_handle *h, unsigned int domid, unsigned long mfn, - unsigned int eventchn, - const char *path); - + unsigned int eventchn); /* Release a domain. * Tells the store domain to release the memory page to the domain. */ -- 2.30.2